#include "log.h"
#include "FreeRTOS.h"
#include "task.h"
#include "cmsis_os.h"
#include <stdint.h>

#ifdef __GNUC__
  #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
  #define GETCHAR_PROTOTYPE int __io_getchar(int ch)
#else
  #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
  #define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#endif /* __GNUC__ */

/* 日志串口全局变量结构体 */
LogUartConfig uart1, uart2, uart3;
LogUartConfig* current_logUart = &uart1; // 默认使用 uart1

/**
  * @brief  日志串口选择函数
  *
  * @param  NULL
  * @return logUart 返回类型为LogUartConfig的结构体
  */
static LogUartConfig* Log_get_UartConfig(int num) {
  switch (num) {
    case 1:
      uart1.usart = USART1; uart1.irqn = USART1_IRQn;
      uart1.gpio = GPIOA; uart1.txPin = GPIO_PIN_9; uart1.rxPin = GPIO_PIN_10;
      return &uart1;
    case 2:
      uart2.usart = USART2; uart2.irqn = USART2_IRQn;
      uart2.gpio = GPIOA; uart2.txPin = GPIO_PIN_2; uart2.rxPin = GPIO_PIN_3;
      return &uart2;
    case 3:
      uart3.usart = USART3; uart3.irqn = USART3_IRQn;
      uart3.gpio = GPIOB; uart3.txPin = GPIO_PIN_10; uart3.rxPin = GPIO_PIN_11;
      return &uart3;
    default:
      return NULL; // 如果 num 不在范围内，返回 NULL
  }
}

/**
  * @brief  日志串口GPIO初始化函数
  *
  * @param  logUart LogUartConfig类型的结构体指针
  * @return NULL
  */
static void Log_initGpio(LogUartConfig *logUart) {
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  GPIO_InitStruct.Pin = logUart->txPin;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(logUart->gpio, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = logUart->rxPin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(logUart->gpio, &GPIO_InitStruct);
}

/**
  * @brief  日志串口Uart_Handle初始化函数
  *
  * @param  logUart LogUartConfig类型的结构体指针
  * @param  My_BaudRate 日志串口波特率
  * @return HAL_OK 初始化成功, HAL_ERROR 初始化失败
  */
static int Log_initUart_Handle(LogUartConfig *logUart, \
                                int           My_BaudRate) {
  logUart->handle.Instance = logUart->usart;
  logUart->handle.Init.BaudRate = My_BaudRate;
  logUart->handle.Init.WordLength = UART_WORDLENGTH_8B;
  logUart->handle.Init.StopBits = UART_STOPBITS_1;
  logUart->handle.Init.Parity = UART_PARITY_NONE;
  logUart->handle.Init.Mode = UART_MODE_TX_RX;
  logUart->handle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  logUart->handle.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_OK == HAL_UART_Init(&logUart->handle)) {
    return HAL_OK;
  }
  return HAL_ERROR;
}

/**
  * @brief  日志串口使能时钟函数
  *
  * @param  logUart LogUartConfig类型的结构体指针
  * @return NULL
  */
static void Log_enableClock(LogUartConfig *logUart) {
  if (logUart->usart == USART1) {
    __HAL_RCC_USART1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
  } else if (logUart->usart == USART2) {
    __HAL_RCC_USART2_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
  } else if (logUart->usart == USART3) {
    __HAL_RCC_USART3_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
  }
}

/**
  * @brief  日志串口禁用时钟函数
  *
  * @param  logUart LogUartConfig类型的结构体指针
  * @return NULL
  */
static void Log_disableClock(LogUartConfig *logUart) {
  if (logUart->usart == USART1) {
    __HAL_RCC_USART1_CLK_DISABLE();
  } else if (logUart->usart == USART2) {
    __HAL_RCC_USART2_CLK_DISABLE();
  } else if (logUart->usart == USART3) {
    __HAL_RCC_USART3_CLK_DISABLE();
  }
}

/**
  * @brief  日志串口初始化中断函数
  *
  * @param  logUart LogUartConfig类型的结构体指针
  * @param  PreemptPriority 抢占优先级
  * @param  SubPriority 相应优先级
  * @return NULL
  */
static void Log_initInterrupt(LogUartConfig *logUart, \
                              uint32_t      PreemptPriority, \
                              uint32_t SubPriority) {
  HAL_NVIC_SetPriority(logUart->irqn, PreemptPriority, SubPriority);
  HAL_NVIC_EnableIRQ(logUart->irqn);
}

/**
  * @brief  日志串口禁用中断函数
  *
  * @param  logUart LogUartConfig类型的结构体指针
  * @return NULL
  */
static void Log_disableInterrupt(LogUartConfig *logUart) {
  HAL_NVIC_DisableIRQ(logUart->irqn);
}

/**
  * @brief  日志串口初始化函数
  *
  * @param  My_BaudRate 日志串口波特率
  * @return HAL_OK 初始化成功,  HAL_ERROR 初始化失败
  */
int Log_USART_Init(int My_BaudRate) {
	LogUartConfig* logUart = Log_get_UartConfig(LOG_USART_CHOICE_NUM); // 获取配置
	if (logUart == NULL) {
		return HAL_ERROR; // 如果返回 NULL，表示无效的 num
	}
	Log_initGpio(logUart);
	Log_enableClock(logUart);
	if (HAL_OK == Log_initUart_Handle(logUart, My_BaudRate)) {
		current_logUart = logUart; // 设置当前使用的 UART
		return HAL_OK;
	}
	Log_disableClock(logUart);
	Log_disableInterrupt(logUart);
	return HAL_ERROR;
}

/**
 * @brief  切换当前使用的 UART
 * 
 * @param  num 选择的串口编号
 * @return NULL
 */
void Log_setCurrentUart(int num) {
	LogUartConfig* logUart = Log_get_UartConfig(num);
	if (logUart != NULL) {
		current_logUart = logUart; // 设置当前串口
	}
}

/**
  * @brief  printf()重定义扩展函数
  *
  * printf("c") -> __io_putchar('c') -> ch = 'c'
  *
  * @param  fmt 打印信息
  * @return HAL_ERROR 初始化失败
  */
PUTCHAR_PROTOTYPE {
    if (HAL_UART_Transmit(&current_logUart->handle, (uint8_t *)&ch, 1, HAL_MAX_DELAY) == HAL_OK)
        return ch;
    return HAL_ERROR;
}

/**
  * @brief  getchar()重定义扩展函数
  *
  * getchar() -> __io_getchar() -> 从串口读取一个字符
  *
  * @param  fmt 接收信息
  * @return HAL_ERROR 初始化失败
  */
GETCHAR_PROTOTYPE {
    char ch;
    if (HAL_UART_Receive(&current_logUart->handle, (uint8_t *)&ch, 1, HAL_MAX_DELAY) == HAL_OK)
        return ch;
    return HAL_ERROR;
}
